package com.own.business.wallet.business.service.impl;

import com.alibaba.fastjson2.JSON;
import com.own.business.pay.common.constant.ConstantPay;
import com.own.business.pay.common.em.PayEnum;
import com.own.business.pay.common.exception.PayException;
import com.own.business.pay.core.aop.AopPayService;
import com.own.business.pay.core.base.BasePayService;
import com.own.business.pay.core.model.PayOrderModel;
import com.own.business.pay.core.model.PayResultModel;
import com.own.business.pay.core.model.RefundOrderModel;
import com.own.business.pay.core.service.BillHistoryService;
import com.own.business.pay.entity.po.BillHistory;
import com.own.business.wallet.business.entity.PayResultEntity;
import com.own.business.wallet.business.entity.WalletPayOrderForm;
import com.own.business.wallet.business.entity.WalletRefundOrderForm;
import com.own.business.wallet.business.service.WalletHistoryService;
import com.own.business.wallet.business.util.WalletBusinessUtil;
import com.own.business.wallet.business.util.lock.OrderLockUtil;
import com.own.business.wallet.common.exception.WalletException;
import com.own.business.wallet.common.property.WalletPayProperty;
import com.own.business.wallet.entity.po.WalletHistory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * WalletPayServiceImpl
 *
 * @author chenxueli
 * @date 2023-08-28 16:29:33
 */
@Slf4j
@Component
@AopPayService(PayEnum.Method.BALANCE)
public class WalletPayServiceImpl implements BasePayService {

    @Resource
    private WalletPayProperty walletPayProperty;

    @Resource
    private WalletBusinessUtil walletBusinessUtil;
    @Resource
    private WalletHistoryService walletHistoryService;
    @Resource
    private BillHistoryService billHistoryService;

    @Resource
    private OrderLockUtil orderLockUtil;

    /**
     * 支出方法
     *
     * @param type  支付方式
     * @param model 支付订单
     * @return 支付凭证
     */
    @Override
    public PayResultModel pay(PayEnum.Type type, PayOrderModel model) {
        // 根据对应的方式生成订单信息
        var orderForm = new WalletPayOrderForm();
        orderForm.setOutTradeNo(model.getTradeNo());
        orderForm.setSubject(model.getSubject());
        orderForm.setBody(model.getBody());
        orderForm.setTotalAmount(model.getTotalAmount().intValue());
        orderForm.setExpireTime(LocalDateTime.now().plusMinutes(30));
        var content = walletBusinessUtil.createPayOrder(model.getUserId(), orderForm);
        return new PayResultModel(model.getTradeNo(), content);
    }

    /**
     * 收入方法（提现）
     *
     * @param model 收入订单
     */
    @Override
    public void income(PayOrderModel model) {
        // 根据对应的方式生成订单信息
        var orderForm = new WalletPayOrderForm();
        orderForm.setOutTradeNo(model.getTradeNo());
        orderForm.setSubject(model.getSubject());
        orderForm.setBody(model.getBody());
        orderForm.setTotalAmount(model.getTotalAmount().intValue());
        orderForm.setExpireTime(LocalDateTime.now().plusYears(7));
        walletBusinessUtil.executeIncomeOrder(model.getUserId(), orderForm);
    }

    /**
     * 查询订单
     *
     * @param outTradeNo 商户订单号
     * @return 账单信息
     */
    @Override
    public BillHistory query(String outTradeNo) {
        var bill = billHistoryService.getByTradeNo(outTradeNo);
        var history = walletHistoryService.getByOutTradeNo(outTradeNo);
        return handlerPayComplete(bill, outTradeNo, history);
    }

    /**
     * 订单退款
     *
     * @param outTradeNo 商户订单
     * @param model      退款信息
     */
    @Override
    public void refund(String outTradeNo, RefundOrderModel model) {
        var orderForm = new WalletRefundOrderForm();
        orderForm.setOutRefundNo(model.getRefundNo());
        orderForm.setOutTradeNo(outTradeNo);
        orderForm.setReason(model.getReason());
        orderForm.setTotalAmount(model.getRefund().intValue());
        walletBusinessUtil.executeRefundOrder(model.getUserId(), orderForm);
    }

    /**
     * 查询单笔退款信息
     *
     * @param outTradeNo  商户订单
     * @param outRefundNo 商户退款单号
     * @return 账单信息
     */
    @Override
    public BillHistory queryRefund(String outTradeNo, String outRefundNo) {
        var bill = billHistoryService.getByRefundNo(outRefundNo);
        var history = walletHistoryService.getByOutRefundNo(outTradeNo);
        return handlerPayComplete(bill, outTradeNo, history);
    }

    /**
     * 关闭订单
     *
     * @param outTradeNo 商户订单号
     */
    @Override
    public void close(String outTradeNo) {
        // 锁定订单信息
        orderLockUtil.lock(outTradeNo, () -> {
            var history = walletHistoryService.getByOutTradeNo(outTradeNo);
            if (history == null) {
                throw new WalletException("没有找到对应的订单信息");
            }
            if (ConstantPay.Status.NEW_BUILT != history.getStatus()) {
                throw new WalletException("订单状态不正确");
            }
            // 修改订单状态
            history.setStatus(ConstantPay.Status.COMPLETE_CLOSE);
            walletHistoryService.update(history);
        });
    }

    /**
     * 处理订单支付完成的事件
     *
     * @param bill       订单信息
     * @param outTradeNo 商户订单号
     * @param history    支付流水信息
     * @return 订单信息
     */
    public BillHistory handlerPayComplete(BillHistory bill, String outTradeNo, WalletHistory history) {
        if (bill == null) {
            bill = billHistoryService.getByTradeNo(outTradeNo);
            if (bill == null) {
                throw new PayException("支付订单信息不存在");
            }
        }
        if (history == null) {
            throw new PayException("支付流水信息不存在");
        }
        var status = history.getStatus();
        switch (status) {
            case ConstantPay.Status.COMPLETE_SUCCESS -> {
                // 如果是已经完成的订单直接返回信息
                bill.setStatus(ConstantPay.Status.COMPLETE_SUCCESS);
                bill.setNotifyData(JSON.toJSONString(new PayResultEntity(history)));
                bill.setTradeTime(history.getPayTime());
                billHistoryService.update(bill);
                // 处理支付成功的业务
                walletBusinessUtil.notify(history.getType(), history.getOutTradeNo(), history.getOutRefundNo());
            }
            case ConstantPay.Status.COMPLETE_CLOSE, ConstantPay.Status.COMPLETE_TIMEOUT -> {
                bill.setStatus(status);
                bill.setNotifyData(null);
                bill.setTradeTime(history.getPayTime());
                billHistoryService.update(bill);
            }
        }
        return bill;
    }

    /**
     * 处理订单支付完成的事件
     *
     * @param bill       订单信息
     * @param outTradeNo 商户订单号
     * @param history    支付流水信息
     * @return 订单信息
     */
    public BillHistory handlerRefundComplete(BillHistory bill, String outTradeNo, WalletHistory history) {
        if (bill == null) {
            bill = billHistoryService.getByRefundNo(outTradeNo);
            if (bill == null) {
                throw new PayException("退款订单信息不存在");
            }
        }
        if (history == null) {
            throw new PayException("退款流水信息不存在");
        }
        var status = history.getStatus();
        switch (status) {
            case ConstantPay.Status.COMPLETE_SUCCESS -> {
                // 如果是已经完成的订单直接返回信息
                bill.setStatus(ConstantPay.Status.COMPLETE_SUCCESS);
                bill.setNotifyData(JSON.toJSONString(new PayResultEntity(history)));
                bill.setTradeTime(history.getPayTime());
                billHistoryService.update(bill);
                // 处理支付成功的业务
                walletBusinessUtil.notify(history.getType(), history.getOutTradeNo(), history.getOutRefundNo());
            }
            case ConstantPay.Status.COMPLETE_CLOSE, ConstantPay.Status.COMPLETE_TIMEOUT -> {
                bill.setStatus(status);
                bill.setNotifyData(null);
                bill.setTradeTime(history.getPayTime());
                billHistoryService.update(bill);
            }
        }
        return bill;
    }

}
